package naga.x.util;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import gnu.trove.map.TObjectLongMap;
import gnu.trove.map.hash.TObjectLongHashMap;
import naga.x.game.time.TimeUpdater;

public class ThreadPool {

	protected ExecutorService pool;
	protected static final Logger LOG = LoggerFactory.getLogger(ThreadPool.class);
	
	protected static class Pool extends ThreadPoolExecutor {

		protected TObjectLongMap<Runnable> records = new TObjectLongHashMap<Runnable>();
		
		public Pool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
			super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
		}
		
		@Override
		protected void beforeExecute(Thread t, Runnable r) {
			synchronized (records) {
				records.put(r, TimeUpdater.getInstance().utc());
			}
		}

		@Override
		protected void afterExecute(Runnable r, Throwable t) {
			long l;
			synchronized (records) {
				l = TimeUpdater.getInstance().utc() - records.remove(r);
			}
			if (l > 10000) { // 超过10s打印日志
				LOG.info("[ASYNC TOO LONG]CLASS[{}]TIME[{}]", r.toString(), l);
			}
		}
	}
	
	protected static class AsyncRunner implements Runnable {

		private Runnable runner;
		
		public AsyncRunner(Runnable runner) {
			this.runner = runner;
		}
		
		@Override
		public void run() {
			try {
				runner.run();
			} catch (Exception e) {
				LOG.error("[THREAD POOL ERROR]CLASS[" + runner.getClass().getName() + "]", e);
			}
		}

		@Override
		public String toString() {
			return runner.getClass().getName();
		}
		
	}
	
	public ThreadPool() {
		this(8, 8);
	}
	
	public ThreadPool(int core, int max) {
		pool = new Pool(core, max, 1L, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
	}
	
	public void execute(Runnable run) {
		pool.execute(new AsyncRunner(run));
	}

	public void shutdown() {
		if (!pool.isShutdown()) {
			pool.shutdown();
		}
	}

}
